package cn.dvptech.remotemate.screenmirror.server;

import android.os.SystemClock;
import android.text.TextUtils;
import android.util.Log;
import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;

import cn.dvptech.remotemate.screenmirror.decode.H264AacDecoder;
import cn.dvptech.remotemate.screenmirror.listener.OnConnectionStateChangeListener;
import cn.dvptech.remotemate.screenmirror.listener.OnFrameReceivedListener;
import cn.dvptech.remotemate.screenmirror.screenHelper.Frame;
import timber.log.Timber;

public class AcceptH264MsgThread extends Thread {
    private final String TAG = "AcceptH264MsgThread";
    private InputStream inputStream;
    private OutputStream outputStream;
    private volatile boolean isRunning = true;
    private OnFrameReceivedListener listener;
    private OnConnectionStateChangeListener mStateChangeListener;
    private H264AacDecoder mDecoder;

    public AcceptH264MsgThread(InputStream is, OutputStream outputStream, OnFrameReceivedListener listener, OnConnectionStateChangeListener disconnectListenerlistener) {
        this.inputStream = is;
        this.outputStream = outputStream;
        this.listener = listener;
        this.mStateChangeListener = disconnectListenerlistener;
        mDecoder = new H264AacDecoder();
        mDecoder.setOnVideoListener(new H264AacDecoder.OnVideoListener() {
            @Override
            public void onSpsPps(byte[] sps, byte[] pps) {
                Frame spsPpsFrame = new Frame();
                spsPpsFrame.setType(Frame.SPSPPS);
                spsPpsFrame.setSps(sps);
                spsPpsFrame.setPps(pps);
                AcceptH264MsgThread.this.listener.acceptBuff(spsPpsFrame);
            }

            @Override
            public void onVideo(byte[] video, int type) {
                Frame frame = new Frame();
                switch (type) {
                    case Frame.KEY_FRAME:
                        frame.setType(Frame.KEY_FRAME);
                        frame.setBytes(video);
                        AcceptH264MsgThread.this.listener.acceptBuff(frame);
                        break;
                    case Frame.NORMAL_FRAME:
                        frame.setType(Frame.NORMAL_FRAME);
                        frame.setBytes(video);
                        AcceptH264MsgThread.this.listener.acceptBuff(frame);
                        break;
                    case Frame.AUDIO_FRAME:
                        frame.setType(Frame.AUDIO_FRAME);
                        frame.setBytes(video);
//                        Timber.d("audio frame ...");
                        AcceptH264MsgThread.this.listener.acceptBuff(frame);
                        break;
                    default:
                        Timber.tag("AcceptH264MsgThread").e("other video...");
                        break;
                }

            }
        });
    }

    @Override
    public void run() {
        super.run();
        byte[] ok = "OK".getBytes();
        try {
            outputStream.write(ok);
            if (mStateChangeListener != null) mStateChangeListener.acceptTcpConnect();
            while (isRunning) {
                // 读取数据类型
                byte[] dataType = readBytes(inputStream, 1);
                String sType = new String(dataType);
                if (TextUtils.isEmpty(sType)) {
                    SystemClock.sleep(1);
                    continue;
                }

                byte[] length = readBytes(inputStream, 4);
                if (length.length == 0) {
                    SystemClock.sleep(1);
                    continue;
                }
                int buffLength = bytesToInt(length);
                switch (sType){
                    case "1":
                        // 视频
                        byte[] buff = readBytes(inputStream, buffLength);
                        mDecoder.decodeH264(buff);
                        break;
                    case "2":
                        // 字符串
                        byte[] buffString = readBytes(inputStream, buffLength);
//                        Timber.tag(TAG).e("accept string...%s", new String(buffString));
                        listener.acceptString(new String(buffString));
                        break;
                    default:
                        break;
                }
            }
        } catch (IOException e) {
            Timber.tag(TAG).e("read and write buff exception = %s", e.toString());
            if (mStateChangeListener != null) mStateChangeListener.acceptTcpDisConnect(e);
        } finally {
            isRunning = false;
        }
    }

    public void shutdown() {
        isRunning = false;
        this.interrupt();
    }

//    private byte[] readByte(InputStream is, int readSize) throws IOException {
//        byte[] buff = new byte[readSize];
//        int len = 0;
//        int eachLen = 0;
//        ByteArrayOutputStream baos = new ByteArrayOutputStream();
//        while (len < readSize) {
//            eachLen = is.read(buff);
//            if (eachLen != -1) {
//                len += eachLen;
//                baos.write(buff, 0, eachLen);
//            } else {
//                baos.close();
//                throw new IOException(TAG + "   :tcp have disconnect...");
//            }
//            if (len < readSize) {
//                buff = new byte[readSize - len];
//            }
//        }
//        byte[] b = baos.toByteArray();
//        baos.close();
//        return b;
//    }

    /**
     * 保证从流里读到指定长度数据
     *
     * @param is
     * @param readSize
     * @return
     * @throws Exception
     */
    private byte[] readBytes(InputStream is, int readSize) throws IOException {
        ByteArrayOutputStream baoS = new ByteArrayOutputStream();
        byte[] buffer = new byte[1024]; // 使用一个合理大小的缓冲区
        int bytesRead;
        int totalBytesRead = 0;

        while (totalBytesRead < readSize &&
                (bytesRead = is.read(buffer, 0, Math.min(buffer.length, readSize - totalBytesRead))) != -1) {
            baoS.write(buffer, 0, bytesRead);
            totalBytesRead += bytesRead;
        }

        if (totalBytesRead < readSize) {
            baoS.close();
            throw new IOException(TAG + " :tcp have disconnect...");
        }

        byte[] result = baoS.toByteArray();
        baoS.close();
        return result;
    }

    /**
     * byte数组中取int数值，本方法适用于(低位在前，高位在后)的顺序，和和intToBytes（）配套使用
     *
     * @param src byte数组
     * @return int数值
     */
    public static int bytesToInt(byte[] src) {
        int value;
        value = (int) ((src[0] & 0xFF)
                | ((src[1] & 0xFF) << 8)
                | ((src[2] & 0xFF) << 16)
                | ((src[3] & 0xFF) << 24));
        return value;
    }
}
